﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using NetWork.Sockets;
using NetWork.Layer;
using NetWork.Sockets.Event;
using NetWork.Sockets.Event.Msg;

namespace NetWork
{


    public delegate void SocketConnectCallback(int ret);
    public class SocketController
    {
        private SocketTool socketTool;
        private SocketState socketState = SocketState.NONE;
        private EventManger eventManager;
        private string name;
        private SocketConnectCallback connCallback = null;
        private float lastActiveTime = 0;
        private float Max_Space_Time = 15;
        private bool needReconnect = true;

        public string Name
        {
            get
            {
                return name;
            }
        }

        public SocketController(string name,bool needReconnect = true)
        {
            this.needReconnect = true;
            this.name = name;
            eventManager = new EventManger();
        }

        public void RegisterMsgListener(int nMsgId, DelegateFunc Handler)
        {
            eventManager.RegisterMsgListener(nMsgId, Handler);
        }

        public void UnregisterMsgListener(int msgId, DelegateFunc handler)
        {
            eventManager.UnRegistMsgListener(msgId, handler);
        }

        public void Connect(string sServerIP, int nHost, NetWork.SocketConnectCallback func = null)
        {

            socketTool = new NetWork.Layer.SocketTool(name, sServerIP, nHost);
            connCallback = func;
            socketTool.Connect();
            lastActiveTime = Time.unscaledTime;
        }
        
        public void Send(int opCode, object data)
        {
            if(socketTool != null)
            {
                socketTool.SendMessage(opCode, data);
                lastActiveTime = Time.unscaledTime;
            }
        }

        public void Disconnect()
        {
            if(socketTool != null)
            {
                socketTool.Close();
            }
        }

        public void ReConnect(SocketConnectCallback func = null)
        {
            socketTool.Reconnect(StaticData.socketIp,StaticData.socketPort);
            connCallback = func;
            lastActiveTime = Time.unscaledTime;
        }

        public void Tick()
        {
            if(socketTool == null)
            {
                return;
            }
            if (socketTool.connJustComplete)
            {
                socketTool.connJustComplete = false;
                if (connCallback != null)
                {
                    int ret = 1;
                    if (socketTool.State == SocketState.WORKING)
                    {
                        ret = 0;
                    }
                    else if (socketTool.State == SocketState.ERROR)
                    {
                        if (needReconnect)
                        {
                            NetAPI.ShowNeedSocketConnect(true);
                        }
                    }
                    connCallback(ret);
                }
                
            }

            PutPacketToEventPool();
            DealWithError();

            switch (socketTool.State)
            {
                case SocketState.ERROR:
                    if (socketState != SocketState.ERROR)
                    {
                        if(needReconnect)
                        {
                            NetAPI.ShowNeedSocketConnect(true);
                        }
                    }
                    break;
                case SocketState.CLOSE:
                    if (socketState == SocketState.WORKING)
                    {
                        if(needReconnect)
                        {
                            NetAPI.ShowNeedSocketConnect();
                        }
                        else
                        {
                            Debug.LogError("socket "+ name+ " closed ");
                        }
                    }
                    break;
                case SocketState.WORKING:
                    if(Time.unscaledTime - lastActiveTime >= Max_Space_Time)
                    {
                        lastActiveTime = Time.unscaledTime;
                        ProtoBuf.Message.CSPingTcp pt = new ProtoBuf.Message.CSPingTcp();
                        pt.clientTime = System.DateTime.UtcNow.Ticks / 10000;
                        socketTool.SendMessage(ProtoBuf.Message.OpDefine.CSPingTcp,pt);
                    }
                    break;
                default:
                    break;
            }
            eventManager.Tick();
            socketState = socketTool.State;
        }

        public void DealWithError()
        {
            var er = socketTool.CheckError();
            if(er != null)
            {
                NetAPI.ShowNetErrorBox(LanguageTool.GetTextNoUpdate(er.errorCode));
            }
        }

        private void PutPacketToEventPool()
        {
            Packets.Packet packet = socketTool.CheckReceivePacket();
            while (packet != null)
            {
                eventManager.AddPacket(packet);
                packet = socketTool.CheckReceivePacket();
            }
        }

        public bool IsConnected()
        {
            return socketTool.Connected;
        }
    }
}